namespace graph_virtual
{
   namespace details
   {
      struct bucket_t
      {
         void update_last_used();
         void unload_graph();
         void set_graph(graph_basic::graph_t* graph);
         bool get_loaded() const;
         boost::posix_time::ptime get_last_used() const;
         void set_inf(graph_basic::details::graph_inf_t inf);
         graph_basic::details::graph_inf_t& get_inf();
         graph_basic::details::graph_inf_t const & get_inf() const;
         graph_basic::graph_t const & get_graph() const;
         graph_basic::graph_t& get_graph();
         graph_basic::graph_ptr_t const get_graph_ptr() const;
         
         bucket_t();
         bucket_t(graph_basic::details::graph_inf_t inf);
         bucket_t(graph_basic::details::graph_inf_t inf, graph_basic::graph_t* graph);
      private:
         graph_basic::details::graph_inf_t inf_;
         boost::shared_ptr<graph_basic::graph_t> graph_;
         boost::posix_time::ptime last_used_;
         bool loaded_;
      };
      typedef boost::shared_ptr<bucket_t> bucket_ptr_t;
      struct virtual_graph_friend_t;
   }


struct virtual_graph_view_t;
struct virtual_graph_t
{  
   virtual_graph_t(std::string db_name, size_t max_loaded_bucket_count);
   ~virtual_graph_t();       
   graph_basic::graph_int_t get_vertex_count(graph_basic::graph_id_t id) const;
   graph_basic::vertex_t const & operator[](graph_basic::vertex_id_t id) const;
   graph_basic::vertex_t& operator[](graph_basic::vertex_id_t id);
   graph_basic::vertex_t const & get_vertex_by_id(graph_basic::vertex_id_t id) const;
   graph_basic::vertex_t& get_vertex_by_id(graph_basic::vertex_id_t id);
   
private:
   typedef std::vector<details::bucket_t> bucket_list_t;
   bucket_list_t buckets_;
   size_t const MAX_LOADABLE_BUCKET_COUNT;
   size_t loaded_count_;
   std::string db_name_;
   sqlite3* db_;
   sqlite3_stmt* stmt_get_bucket_by_id_;
   char* sql_get_bucket_by_id_;
   char const** pzTail_;
   
   graph_basic::graph_int_t get_bucket_count() const;
   details::bucket_t const & get_random_non_empty_bucket() const;
   details::bucket_t& get_random_non_empty_bucket();
   void init();
   void load_bucket_from_db(graph_basic::graph_id_t id);
   void unload_suitable_bucket();
   graph_basic::details::graph_inf_t const & get_bucket_info(graph_basic::graph_id_t id) const;
   graph_basic::details::graph_inf_t& get_bucket_info(graph_basic::graph_id_t id);
   details::bucket_t& get_bucket(graph_basic::graph_id_t id);
   details::bucket_t const & get_bucket(graph_basic::graph_id_t id) const;
   graph_basic::graph_id_t find_bucket(graph_basic::point_t p);
   graph_basic::graph_id_t const find_bucket(graph_basic::point_t p) const;
   graph_basic::point_t get_bucket_square_size() const;
   
   friend graph_basic::vertex_t& source(graph_basic::edge_t e, virtual_graph_t& g);
   friend graph_basic::vertex_t& target(graph_basic::edge_t e, virtual_graph_t& g);
   friend graph_basic::vertex_id_pair_t nearest_vertices(virtual_graph_t const & graph, 
                     graph_basic::point_t first_p, graph_basic::point_t second_p);
   friend graph_basic::vertex_id_pair_t nearest_vertices(virtual_graph_view_t const & graph, 
                     graph_basic::point_t first_p, graph_basic::point_t second_p);
   
   friend struct virtual_vertex_iterator_t;
   friend struct virtual_edge_iterator_t;
   friend struct virtual_adjacent_vertices_iterator_t;
   friend struct virtual_adjacent_edges_iterator_t;
   friend struct details::virtual_graph_friend_t;
};  

typedef boost::shared_ptr<virtual_graph_t> virtual_graph_ptr_t;

inline graph_basic::vertex_t& source(graph_basic::edge_t e, virtual_graph_t& g);
inline graph_basic::vertex_t const & source(graph_basic::edge_t const e, virtual_graph_t const & g);
inline graph_basic::vertex_t& target(graph_basic::edge_t e, virtual_graph_t& g);
inline graph_basic::vertex_t const & target(graph_basic::edge_t const e, virtual_graph_t const & g);

inline graph_basic::vertex_id_pair_t nearest_vertices(virtual_graph_t const & graph, 
                                                      graph_basic::point_t first_p, graph_basic::point_t second_p);

template<class G>
struct graph_traits
{
   struct some_iterator_t;
   typedef some_iterator_t vertex_iterator;
   typedef some_iterator_t edge_iterator;
   typedef some_iterator_t adj_vertices_iterator;
   typedef some_iterator_t adj_edges_iterator;
   struct ERROR_NOT_SUPPORTED_GRAPH_TYPE;
   ERROR_NOT_SUPPORTED_GRAPH_TYPE err;
};

   namespace details
   {
      struct virtual_graph_friend_t
      {
         static graph_basic::point_t get_bucket_square_size(virtual_graph_t& graph)
         {
            return graph.get_bucket_square_size();
         }
         static graph_basic::details::graph_inf_t& get_bucket_info
                     (virtual_graph_t& graph, graph_basic::graph_id_t id)
         {
            return graph.get_bucket_info(id);
         }
         static details::bucket_t const & get_bucket
                     (virtual_graph_t const & graph, graph_basic::graph_id_t id)
         {
            return graph.get_bucket(id);
         }
         static graph_basic::graph_id_t const find_bucket(virtual_graph_t const & graph, graph_basic::point_t p)
         {
            return graph.find_bucket(p);
         }
         static graph_basic::graph_int_t get_bucket_count(virtual_graph_t const & graph)
         {
            return graph.get_bucket_count();
         }
         static details::bucket_t const & get_random_non_empty_bucket(virtual_graph_t const & graph)
         {
            return graph.get_random_non_empty_bucket();
         }
      };
   }
}